/*************************************************
Author: Aven
Date: 12/03/2013
Description:
Notes:
*************************************************/

#ifndef __CAuctionMgr_h__
#define __CAuctionMgr_h__

#include "commerrno.h"
#include "commmsg.h"
#include "CActCfg.h"
#include "CAuctionCfg.h"
#include "MsgAuction.pb.h"

//每轮竞拍时长(秒数)
#define AUCTION_SECONS_PER_ROUND  3600


class CAucBidKey
{
public:
    CAucBidKey ()
    {
        _ucMoneyType = 0;
        _iMoney = 0;
    }

    unsigned char _ucMoneyType;
    int _iMoney;

    bool operator==(const CAucBidKey& stKey) const
    {
        return (_ucMoneyType == stKey._ucMoneyType && _iMoney == stKey._iMoney);
    }
};

namespace __gnu_cxx
{
    template<> struct hash<CAucBidKey>
    {
        size_t operator()(const CAucBidKey& x) const
        {
            return (x._ucMoneyType * 100000 + x._iMoney);
        }
    };
}

#define BLIND_AUCTION_HASH_SIZE  (2 * MAX_REGISTER_PLAYER)   //暗拍HASH的大小
class CAuctionBlindData
{
public:
    CAuctionBlindData()
    {
        _bHashInited = false;

        Clear(true);
    }

    //暗拍活动结算时_astNeedBackMoneyGid 由异步命令Clear, 所以需要传入判断
    void Clear(bool bClearBackMoneyGid)
    {
        if (_bHashInited)
        {
            int iIndex = 0;
            while((iIndex = _hPrice2Gid.GetHeadIndex())>=0)
            {
                _hPrice2Gid.HashFreeByIndex(iIndex);
            }
        }

        if (bClearBackMoneyGid)
        {
            _astNeedBackMoneyGid.Clear();
        }

        _iSilverBidCnt = 0;
        _iGoldBidCnt = 0;
    }

    int Init(const char* szBuff)
    {
        int iRet = 0;
        int iOffset = 0;

        iRet = _hPrice2Gid.Init(szBuff+iOffset, BLIND_AUCTION_HASH_SIZE);
        CT_RETURN(iRet);
        iOffset += CTLib::CTHashObjectMgr<int, int>::CountSize(BLIND_AUCTION_HASH_SIZE);

        _bHashInited = true;

        Clear(true);

        return iRet;
    }


    static int CountSize()
    {
        int iSize = 0;
        iSize = CTLib::CTHashObjectMgr<CAucBidKey, unsigned int>::CountSize(BLIND_AUCTION_HASH_SIZE);
        return iSize;
    }

    bool IsVailidMoneyType (unsigned char ucMoneyType)
    {
        if (AUCTION_MONEY_TYPE_GOLD == ucMoneyType || AUCTION_MONEY_TYPE_SILVER == ucMoneyType)
        {
            return true;
        }

        return false;
    }

    void AddBackMoneyUser (unsigned int uiGid)
    {
        if (0 == uiGid)
        {
            return ;
        }

        for (int i = 0; i < _astNeedBackMoneyGid.Size(); i++)
        {
            if (_astNeedBackMoneyGid[i] == uiGid)
            {
                return ;
            }
        }

        _astNeedBackMoneyGid.AddOneItem(uiGid);
    }

    //增加新的出价
    int AddBlindBid (unsigned char ucMoneyType, int iMoney, unsigned int uiGid)
    {
        if (!IsVailidMoneyType(ucMoneyType) || iMoney <= 0)
        {
            CT_ERROR (("%d, %d, %d", ucMoneyType, iMoney, uiGid));
            return ERROR_AUCTION_BLIND_HASH;
        }

        CAucBidKey stKey;
        stKey._ucMoneyType = ucMoneyType;
        stKey._iMoney = iMoney;

        int iIndex = _hPrice2Gid.HashFind (stKey);
        if( iIndex < 0 )
        {
            iIndex = _hPrice2Gid.HashAlloc (stKey);
            if( iIndex >= 0 )
            {
                _hPrice2Gid [iIndex] = uiGid;
            }
            else
            {
                CT_ERROR (("%d, %d, %d", stKey._iMoney, stKey._ucMoneyType, uiGid));
                return ERROR_AUCTION_BLIND_HASH;
            }
        }
        else
        {
            CAucBidKey stOldKey = _hPrice2Gid.GetKeyByIndex(iIndex);
            unsigned int uiPrevGid = _hPrice2Gid [iIndex];

            if (stOldKey == stKey)  //存在相同的出价
            {
                AddBackMoneyUser (uiGid);
                AddBackMoneyUser (uiPrevGid);

                _hPrice2Gid[iIndex] = 0;
            }
            else
            {
                CT_ERROR (("%d, %d, %d", stKey._iMoney, stKey._ucMoneyType, stOldKey._iMoney, stOldKey._iMoney));
                return ERROR_AUCTION_BLIND_HASH;
            }
        }


        if (AUCTION_MONEY_TYPE_GOLD == ucMoneyType)
        {
            _iGoldBidCnt += 1;
        }
        else
        {
            _iSilverBidCnt += 1;
        }

        return RET_OK;
    }

    int GetBidCount (unsigned char ucMoneyType)
    {
        if (!IsVailidMoneyType(ucMoneyType))
        {
            return 0;
        }

        return (AUCTION_MONEY_TYPE_GOLD == ucMoneyType ? _iGoldBidCnt : _iSilverBidCnt);
    }

public:
    CTLib::CTHashObjectMgr<CAucBidKey, unsigned int> _hPrice2Gid;     //此出价的用户数, price->users
    CTLib::CTArray<unsigned int, MAX_REGISTER_PLAYER + 1> _astNeedBackMoneyGid;  //需要退款的用户
    int _iSilverBidCnt;
    int _iGoldBidCnt;

    bool _bHashInited;
};

class CDropItem;
class CAuctionMgr
{
    enum MyEnum
    {
        NOTICE_PUBLIC_AUCTION_SECONDS = 300,
        NOTICE_FINAL_AUCTION_SECONDS = 180,
    };
public:

    CAuctionMgr()
    {
        _iLastAuctionEndTime = 0;
        _iAuctionBeginTime = 0;
        _iNeedSendPublicMarTime = 0;
        _iNeedSendFinalMarTime = 0;
    }

    virtual ~CAuctionMgr()
    {
    }

    int Init(const char* szBuff)
    {
        _stBlindData.Init(szBuff);
        return 0;
    }

    int LoadConfig(const char* szCfgPath);

    //获取拍卖商品的配置
    int GetGoodsConfig (unsigned short usGoodsId, CAuctionGoodsUnit & stCfg);

    int CountSize()
    {
        return _stBlindData.CountSize();
    }

    //每秒刷新活动状态
    int InitData (CAuctionCommonData & stAuctionData);

    //每秒刷新活动状态
    int TimeTick (int iNowTime);

    //检查返还金钱在用户登录的时候
    int CheckBackMoneyOnLogin(CPlayerBaseInfo & stPlayerBaseInfo);

    //触发暗拍结算
    int TriggerBlindResult (CAuctionCommonData & stAuctionData, int iNowTime);

    //触发竞拍结算
    int TriggerPublicResult (CAuctionRecord & stRecord, int iNowTime);

    //触发压轴结算
    int TriggerFinalResult(CAuctionCommonData & stAuctionData, int iNowTime);

    //处理异步请求
    int DoReq(MsgReqAuction &stReq, MsgAnsAuction & stAns);

    //高价竞拍
    int PublicAuction (CPlayerBaseInfo & stPlayerBaseInfo,  MsgReqAuction & stReq, MsgAnsAuction & stAns);

    //暗拍竞价
    int BlindAuction (CPlayerBaseInfo & stPlayerBaseInfo,  MsgReqAuction & stReq, MsgAnsAuction & stAns);

    int TriggerPayBackBlindMoney ();

    int PayBackOneUserBlindMoney (CPlayerBaseInfo & stPlayerBaseInfo, CAuctionRecord & stBlind);

    //返还金钱给竞价用户
    int PayBackPublicMoney (CAuctionRecord & stRecord,  int iMoneyType, unsigned int uiNewGid);

    //发货
    void SendGoods(EN_AUCTION_TYPE enType, CAuctionRecord & stRecord);

    //初始化拍卖物品
    int InitAuction(CAuctionCommonData& stZoneAuction, int iNowTime);

    //获取竞拍的轮数. (竞拍结束了返回 0， 大于0为有效的轮数)
    int GetAuctionRound (int iNowTime);

    //获取本轮离拍卖还有多少秒
    int GetRoundEndTime (int iNowTime);

    int GetAuctionRecord (EN_AUCTION_TYPE enType,  int iRound, CAuctionRecord & stRecord);

    int GetAuctionGoodsInfo (CAuctionRecord & stRecord, unsigned char ucMoneType, MsgBidItem & stBidItem);

    int GetPublicGoodsInfo (int iNowTime,  MsgAnsAuction & stAns);
    int GetBlindGoodsInfo (CAuctionUserData & stUserAuction,  MsgAnsAuction & stAns);

    int GetBlindGoodsInfo (CAuctionUserData & stUserData, unsigned char ucMoneType, MsgBidItem & stBidItem);

    int GetAuctionRecordInfo (CAuctionRecord & stRecord, EN_AUCTION_TYPE enType, MsgAuctionRecord & stMsgRecord);

    int GetBidRecordInfo (CAuctionRecord & stRecord, EN_AUCTION_TYPE enType, MsgAuctionRecord & stMsgRecord);

    int GetAuctionItem (CAuctionUserData & stUserAuctionData,  CDropItem & stBonusItem);

    int GetAuctionItemSpace (CAuctionUserData & stUserAuctionData);

    //是否进入压轴竞拍
    bool IsInFinal (int iRound);

    void UpdateData(unsigned int uiGid=0);

    //获取活动信息
    int GetAuctionInfo(CAuctionUserData & GetAuctionInfo, int iOpt, MsgAnsAuction & stAns);

    //获取活动历史
    int GetAuctionHistory (unsigned int uiGid, int iOpt, MsgAnsAuction & stAns);

    //通知地图中所有用户拍卖数据变化
    int NotifyChangeInfo (EN_AUCTION_TYPE enType);

    //出价记录发生变化
    void NotifyBidInfo (unsigned int uiGid = 0);

    //跑马灯信息发生变化
    void NotifyMarInfo (unsigned int uiGid = 0);

    void AddMarRecord (EN_AUCTION_TYPE enType, int iNowTime, CAuctionRecord & stNowRecord);

    void AddBidRecord (CAuctionCommonData & stZoneAuction, CAuctionRecord & stBidHis);

    //是否能进行上一次拍卖的结算
    bool CanTriggerResult (EN_AUCTION_TYPE enType, int iLastCalcTime, int iNowTime);

public:
    CAuctionBlindData     _stBlindData;     //全区的暗拍数据不入库. 用户的出价信息保存在个人身上

private:
    int _iLastAuctionEndTime;        //上次拍卖的结束时间
    int _iAuctionBeginTime;          //拍卖会的开启时间.
    int _iAuctionEndTime;            //拍卖会的结束时间.
    bool _bCanOpenBlind;             //是否能开启暗拍. （服务器异常重启后,暗拍数据无法恢复,需要关闭暗拍功能）

    int _iNeedSendPublicMarTime;             //拍卖会竞拍结束前5分钟增加一条跑马灯
    int _iNeedSendFinalMarTime;              //压轴竞拍开始前3分钟,发送全服跑马灯

    CAuctionConfig        _stAuctionCfg;

    CTArray<CAuctionRecord, MAX_AUCTION_MAR_MSG> _stMarMsg;   //跑马灯信息

    int DeductMoney (CPlayerBaseInfo & stPlayerBaseInfo, CAuctionRecord & stRecord, int iMoneyType, int iMoney);
    int DeductBlindMoney (CPlayerBaseInfo & stPlayerBaseInfo, int iMoneyType, int iMoney);
    int PreCheckBlind (CPlayerBaseInfo & stPlayerBaseInfo, int iMoneyType, int iMoney);
    int PreCheckPublic (CPlayerBaseInfo & stPlayerBaseInfo, CAuctionRecord & stRecord, int iMoneyType, int iMoney);
    void NotifyAuctionMapUsers (unsigned int uiGid, int iOpt, MsgAnsAuction & stAns);
    int GetBeginTimeInCfg ();
    int GetBeginEndInCfg ();
    void CheckAndTriggerResult (CAuctionCommonData & stZoneAuction, int iNowTime);
    void UpdateZoneAuction ();
    void UpdateUserAuction (CPlayerBaseInfo & stPlayerBaseInfo);

    bool IsAuctionOpen (int iNowTime);

    void SendZoneMar (EN_AUCTION_TYPE enType, const CAuctionRecord & stNowRecord);

    void SendAuctionTips (MsgTips& stTips);

    void CheackAndSendMar (CAuctionCommonData & stZoneAuction, int iNowTime);

    void UpdateMarNotifyTime (int iNowTime);
};


#endif //__CAuctionMgr_h__




